package one.beex.robot.client;

import io.broker.api.client.domain.event.DepthEvent;
import com.udojava.evalex.Expression;
import one.beex.robot.symbol.SymbolInfo;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

class RobotKit {

    static BigDecimal getInputPrice(
            @NotNull DepthEvent marketDepth, SymbolInfo symbolInfo) {
        int scale = symbolInfo.getMinPrice().scale();
        BigDecimal askPrice = new BigDecimal(marketDepth.getAsks().get(0).getPrice());
        BigDecimal bidPrice = new BigDecimal(marketDepth.getBids().get(0).getPrice());

        BigDecimal avgPrice = calculateAverage(askPrice, bidPrice, scale);

        BigDecimal saltPrice =
                getRandom(BigDecimal.valueOf(0.3), BigDecimal.valueOf(0.3).negate(), scale)
                        .multiply(
                                askPrice.subtract(bidPrice)
                                        .min(
                                                BigDecimal.valueOf(100)
                                                        .multiply(symbolInfo.getMinPrice())))
                        .divide(BigDecimal.valueOf(2), symbolInfo.getMinPrice().scale(), RoundingMode.FLOOR);

        BigDecimal inputPrice =
                avgPrice.add(saltPrice)
                        .min(
                                askPrice.subtract(
                                        BigDecimal.valueOf(2).multiply(symbolInfo.getMinPrice())));

        return inputPrice.max(
                bidPrice.add(BigDecimal.valueOf(2).multiply(symbolInfo.getMinPrice()))).setScale(scale, RoundingMode.FLOOR);
    }

    static BigDecimal getInputVolume(
            BigDecimal volumeBetween7min, BigDecimal timesBetween7min, SymbolInfo symbolInfo) {
        int scale = symbolInfo.getMinQuantity().scale();

        return symbolInfo
                .getMinQuantity()
                .max(
                        volumeBetween7min
                                .divide(timesBetween7min, scale, RoundingMode.FLOOR)
                                .multiply(
                                        getRandom(
                                                BigDecimal.valueOf(0.2),
                                                BigDecimal.valueOf(1.8),
                                                8))).setScale(scale, RoundingMode.FLOOR);
    }

    private static BigDecimal calculateAverage(BigDecimal askPrice, BigDecimal bidPrice, int scale) {
        Expression expression =
                new Expression("(askPrice+bidPrice)/2", new MathContext(scale, RoundingMode.FLOOR));
        expression.with("askPrice", askPrice);
        expression.with("bidPrice", bidPrice);
        return expression.eval().setScale(scale, RoundingMode.FLOOR);
    }

    static BigDecimal getRandom(BigDecimal max, BigDecimal min, int scale) {
        return new BigDecimal(Math.random() * (max.subtract(min).doubleValue()))
                .add(min)
                .setScale(scale, RoundingMode.FLOOR);
    }
}
